package cn.cucc.gadds.util;

import javax.crypto.*;
import java.io.*;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

public class AESFileUtil {
    /**
     * 密钥算法
     */
    private static final String ALGORITHM = "AES";
    /**
     * 加解密算法/工作模式/填充方式
     */
    private static final String ALGORITHM_STR = "AES/ECB/PKCS5Padding";

    /**
     * init AES Cipher
     *
     * @param password  密码
     * @param cipherMode
     * @return
     */
    public static Cipher initAESCipher(String password, int cipherMode) {
        Cipher cipher = null;
        try {
            SecretKey key = getKey(password);
            cipher = Cipher.getInstance(ALGORITHM_STR);
            cipher.init(cipherMode, key);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        } catch (InvalidKeyException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
        return cipher;
    }

    /**
     * 通过密码获取密钥key
     *
     * @param password 密码
     * @return
     */
    private static SecretKey getKey(String password) {
        //获取一个密钥生成器实例
        KeyGenerator keyGenerator = null;
        try {
            keyGenerator = KeyGenerator.getInstance(ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        SecureRandom random = new SecureRandom();
        random.setSeed(password.getBytes());//设置加密用的种子，密钥
        keyGenerator.init(random);
        SecretKey secretKey = keyGenerator.generateKey();
        return secretKey;
    }


    /**
     * AES 加密文件
     *
     * @param sourceFile 需要加密的文件
     * @param targetFile 加密后的文件
     * @param password   密码
     * @return 加密成功返回<code>true</code>
     */
    public static boolean encryptFile(String sourceFile, String targetFile, String password) {
        File encryptFile = null;
        File decryptfile = null;
        CipherOutputStream cipherOutputStream = null;
        BufferedInputStream bufferedInputStream = null;
        try {
            encryptFile = new File(sourceFile);
            //被加密的文件不存在
            if (!encryptFile.exists()) {
                throw new NullPointerException("Encrypt file is empty");
            }
            decryptfile = new File(targetFile);
            //加密文件已存在
            if (decryptfile.exists()) {
                decryptfile.delete();
            }
            decryptfile.createNewFile();

            Cipher cipher = initAESCipher(password, Cipher.ENCRYPT_MODE);
            cipherOutputStream = new CipherOutputStream(new FileOutputStream(decryptfile), cipher);
            bufferedInputStream = new BufferedInputStream(new FileInputStream(encryptFile));

            byte[] buffer = new byte[1024];
            int bufferLength;

            while ((bufferLength = bufferedInputStream.read(buffer)) != -1) {
                cipherOutputStream.write(buffer, 0, bufferLength);
            }
            bufferedInputStream.close();
            cipherOutputStream.close();
        } catch (IOException e) {
            delFile(decryptfile.getAbsolutePath());
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * AES 解密文件
     *
     * @param sourceFile 原文件
     * @param targetFile
     * @param mKey
     * @return
     */

    public static boolean decryptFile(String sourceFile, String targetFile, String mKey) {
        File encryptFile = null;
        File decryptFile = null;
        BufferedOutputStream outputStream = null;
        CipherInputStream inputStream = null;
        try {
            encryptFile = new File(sourceFile);
            if (!encryptFile.exists()) {
                throw new NullPointerException("source file is empty");
            }
            decryptFile = new File(targetFile);
            if (decryptFile.exists()) {
                decryptFile.delete();
            }
            decryptFile.createNewFile();

            Cipher cipher = initAESCipher(mKey, Cipher.DECRYPT_MODE);

            outputStream = new BufferedOutputStream(new FileOutputStream(decryptFile));
            inputStream = new CipherInputStream(new FileInputStream(encryptFile), cipher);

            int bufferLength;
            byte[] buffer = new byte[1024];

            while ((bufferLength = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bufferLength);
            }
            inputStream.close();
            outputStream.close();
        } catch (IOException e) {
            delFile(decryptFile.getAbsolutePath());
            e.printStackTrace();
            return false;
        }
        return true;
    }


    /**
     * delete File
     *
     * @param pathFile
     * @return
     */
    public static boolean delFile(String pathFile) {
        boolean flag = false;
        if (pathFile == null && pathFile.length() <= 0) {
            throw new NullPointerException("文件不能为空");
        } else {
            File file = new File(pathFile);
            // 路径为文件且不为空则进行删除
            if (file.isFile() && file.exists()) {
                file.delete();
                flag = true;
            }
        }
        return flag;
    }


    public static void main(String[] args) {
        long times = System.currentTimeMillis();
        boolean flag = AESFileUtil.encryptFile
                ("D:/balance_sheet_clean.rar", "D:/balance_sheet_clean.rar.aes", "abc");
        System.out.println(flag);
        System.out.println(System.currentTimeMillis() - times);

        long times2 = System.currentTimeMillis();
        flag = AESFileUtil.decryptFile
                ("D:/balance_sheet_clean.rar.aes", "D:/balance_sheet_clean2.rar", "abc");
        System.out.println(flag);
        System.out.println(System.currentTimeMillis() - times2);
    }

}
